﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ExpressionLanguage
{
    public static class MathLibrary
    {

        private static bool Math_Abs(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1)
                return false;
            double value;

            if (!parameters[0].AsNumber(out value))
                return false;

            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Abs(value));

            return true;
        }

        private static bool Math_Sin(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Sin(value));
            return true;
        }

        private static bool Math_Cos(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Cos(value));
            return true;
        }

        private static bool Math_Tan(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Tan(value));
            return true;
        }

        private static bool Math_Pow(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 2)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            double power;
            if (!parameters[1].AsNumber(out power))
                return false;
            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Pow(value, power));
            return true;
        }

        private static bool Math_Min(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count == 0)
                return false;
            double minValue;
            if (!parameters[0].AsNumber(out minValue))
                return false;
            for (int i = 1; i < parameters.Count; ++i)
            {
                double dValue;
                if (!parameters[i].AsNumber(out dValue))
                    return false;
                if (minValue > dValue)
                    minValue = dValue;
            }
            result = new ExpressionInterpreter.ExecutionStack.Variable(minValue);
            return true;
        }

        private static bool Math_Max(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count == 0)
                return false;
            double maxValue;
            if (!parameters[0].AsNumber(out maxValue))
                return false;
            for (int i = 1; i < parameters.Count; ++i)
            {
                double dValue;
                if (!parameters[i].AsNumber(out dValue))
                    return false;
                if (maxValue < dValue)
                    maxValue = dValue;
            }
            result = new ExpressionInterpreter.ExecutionStack.Variable(maxValue);
            return true;
        }

        private static bool Math_Log(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1 && parameters.Count != 2)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            if (parameters.Count == 1)
            {
                result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Log(value));
                return true;
            }
            else
            {
                double power;
                if (!parameters[1].AsNumber(out power))
                    return false;
                result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Log(value, power));
                return true;
            }
        }

        private static bool Math_Log10(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Log10(value));
            return true;
        }

        private static bool Math_Exp(List<ExpressionInterpreter.ExecutionStack.Variable> parameters, out ExpressionInterpreter.ExecutionStack.Variable result)
        {
            result = ExpressionInterpreter.ExecutionStack.Variable.MakeVoid();

            if (parameters.Count != 1)
                return false;
            double value;
            if (!parameters[0].AsNumber(out value))
                return false;
            result = new ExpressionInterpreter.ExecutionStack.Variable(Math.Exp(value));
            return true;
        }

        public static void LoadLibrary( ExpressionInterpreter.GlobalFunction func , ExpressionInterpreter.ExecutionStack stack )
        {
            stack.AddNumber("Math.PEI", 3.141592653);
            func.RegisterGlobalFunction("Math.Abs", MathLibrary.Math_Abs);
            func.RegisterGlobalFunction("Math.Sin", MathLibrary.Math_Sin);
            func.RegisterGlobalFunction("Math.Cos", MathLibrary.Math_Cos);
            func.RegisterGlobalFunction("Math.Tan", MathLibrary.Math_Tan);
            func.RegisterGlobalFunction("Math.Pow", MathLibrary.Math_Pow);
            func.RegisterGlobalFunction("Math.Min", MathLibrary.Math_Min);
            func.RegisterGlobalFunction("Math.Max", MathLibrary.Math_Max);
            func.RegisterGlobalFunction("Math.Log", MathLibrary.Math_Log);
            func.RegisterGlobalFunction("Math.Log10", MathLibrary.Math_Log10);
            func.RegisterGlobalFunction("Math.Exp", MathLibrary.Math_Exp);
        }
    }
}
